home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.006 / xemacs-1 / lib / xemacs-19.13 / lisp / edebug / cust-print.el < prev    next >
Encoding:
Text File  |  1995-01-31  |  20.4 KB  |  614 lines

  1. ;;; cust-print.el --- handles print-level and print-circle.
  2. ;; Keywords: extensions
  3.  
  4. ;; cust-print.el handles print-level and print-circle.
  5. ;; Copyright (C) 1992 Daniel LaLiberte
  6.  
  7. ;; LCD Archive Entry:
  8. ;; custom-print|Daniel LaLiberte|liberte@cs.uiuc.edu
  9. ;; |Handle print-level, print-circle and more.
  10. ;; |!Date: 1993/01/19 18:38:13 !|!Revision: 1.1 !|
  11.  
  12. ;; This file is not part of GNU Emacs.
  13.  
  14. ;; GNU Emacs is distributed in the hope that it will be useful,
  15. ;; but WITHOUT ANY WARRANTY.  No author or distributor
  16. ;; accepts responsibility to anyone for the consequences of using it
  17. ;; or for whether it serves any particular purpose or works at all,
  18. ;; unless he says so in writing.  Refer to the GNU Emacs General Public
  19. ;; License for full details.
  20.  
  21. ;; Everyone is granted permission to copy, modify and redistribute
  22. ;; GNU Emacs, but only under the conditions described in the
  23. ;; GNU Emacs General Public License.   A copy of this license is
  24. ;; supposed to have been given to you along with GNU Emacs so you
  25. ;; can know your rights and responsibilities.  It should be in a
  26. ;; file named COPYING.  Among other things, the copyright notice
  27. ;; and this notice must be preserved on all copies.
  28.  
  29. ;;=================================================================
  30.  
  31. ;; This package provides a general print handler for prin1 and princ
  32. ;; that supports print-level and print-circle, and by the way,
  33. ;; print-length since the standard routines are being replaced.  Also,
  34. ;; to print custom types constructed from lists and vectors, use
  35. ;; custom-print-list and custom-print-vector.  See the documentation
  36. ;; strings of these variables for more details.  
  37.  
  38. ;; If the results of your expressions contain circular references to
  39. ;; other parts of the same structure, the standard Emacs print
  40. ;; subroutines may fail to print with an untrappable error,
  41. ;; "Apparently circular structure being printed".  If you only use cdr
  42. ;; circular lists (where cdrs of lists point back; what is the right
  43. ;; term here?), you can limit the length of printing with
  44. ;; print-length.  But car circular lists and circular vectors generate
  45. ;; the above mentioned error in Emacs version 18.  Version
  46. ;; 19 supports print-level, but it is often useful to get a better
  47. ;; print representation of circular structures; the print-circle
  48. ;; option may be used to print more concise representations.
  49.  
  50. ;; There are several ways to use this package.  You may replace prin1,
  51. ;; princ, print, prin1-to-string, format, message, and error by
  52. ;; calling install-custom-print-funcs.  Any use of these functions in
  53. ;; lisp code will be affected; later reset with
  54. ;; uninstall-custom-print-funcs.  Or you may temporarily install them
  55. ;; inside the macro with-custom-print-funcs.  Or, you could call the
  56. ;; custom routines directly which have the same names with "custom-"
  57. ;; prepended, thus only affecting the printing that requires them.
  58.  
  59. ;; Note that subroutines which call print subroutines directly will not
  60. ;; use the custom print functions.  In particular, the evaluation
  61. ;; functions like eval-region call the print subroutines directly.
  62. ;; Therefore, evaluating (aref circ-list 0), which calls error
  63. ;; directly (because circ-list is not an array), will jump to the top
  64. ;; level instead of printing the circular list.
  65.  
  66. ;; Obviously the right way to implement this custom-print facility
  67. ;; is in C.  Please volunteer since I don't have the time or need.
  68. ;; This custom-print package might be extended in the future to
  69. ;; handle more Common Lisp like printing capabilities.
  70.  
  71. ;; Implementation design: we want to use the same list and vector
  72. ;; processing algorithm for all versions of prin1 and princ, since how
  73. ;; the processing is done depends on print-length, print-level, and
  74. ;; print-circle.  For circle printing, a preprocessing step is
  75. ;; required before the final printing.  Thanks to Jamie Zawinski
  76. ;; for motivation and algorithms.
  77.  
  78. ;;=========================================================
  79. ;; export list:
  80.  
  81. ;; print-level
  82. ;; print-circle
  83.  
  84. ;; install-custom-print-funcs
  85. ;; uninstall-custom-print-funcs
  86. ;; custom-print-funcs-installed-p
  87. ;; with-custom-print-funcs
  88.  
  89. ;; custom-prin1
  90. ;; custom-princ
  91. ;; custom-prin1-to-string
  92. ;; custom-print
  93. ;; custom-format
  94. ;; custom-message
  95. ;; custom-error
  96.  
  97. ;; custom-print-list
  98. ;; custom-print-vectorp
  99. ;; add-custom-print-list
  100. ;; add-custom-print-vector
  101.  
  102.  
  103. (provide 'cust-print)
  104. ;; Abbreviated package name: "CP"
  105.  
  106. ;;(defvar print-length nil
  107. ;;  "*Controls how many elements of a list, at each level, are printed.
  108. ;;This is defined by emacs.")
  109.  
  110. (defvar print-level nil
  111.   "*Controls how many levels deep a nested data object will print.  
  112.  
  113. If nil, printing proceeds recursively and may lead to
  114. max-lisp-eval-depth being exceeded or an untrappable error may occur:
  115. \"Apparently circular structure being printed.\"   Also see
  116. print-length and print-circle.
  117.  
  118. If non-nil, components at levels equal to or greater than print-level
  119. are printed simply as \"#\".  The object to be printed is at level 0,
  120. and if the object is a list or vector, its top-level components are at
  121. level 1.")
  122.  
  123.  
  124. (defvar print-circle nil
  125.   "*Controls the printing of recursive structures.  
  126.  
  127. If nil, printing proceeds recursively and may lead to
  128. max-lisp-eval-depth being exceeded or an untrappable error may occur:
  129. \"Apparently circular structure being printed.\"  Also see
  130. print-length and print-level.
  131.  
  132. If non-nil, shared substructures anywhere in the structure are printed
  133. with \"#n=\" before the first occurance (in the order of the print
  134. representation) and \"#n#\" in place of each subsequent occurance,
  135. where n is a positive decimal integer.
  136.  
  137. Currently, there is no way to read this representation in Emacs.")
  138.  
  139. (defvar custom-print-vectors nil
  140.   "*Non-nil if printing of vectors should obey print-level and print-length.
  141.  
  142. For Emacs 18, setting print-level, or adding custom print list or
  143. vector handling will make this happen anyway.  Emacs 19 obeys
  144. print-level, but not for vectors.")
  145.  
  146.  
  147. (defconst custom-print-list
  148.   nil
  149.   ;; e.g.  '((floatp . float-to-string))
  150.   "If non-nil, an alist for printing of custom list objects.  
  151. Pairs are of the form (pred . converter).  If the predicate is true
  152. for an object, the converter is called with the object and should
  153. return a string which will be printed with princ.  
  154. Also see custom-print-vector.")
  155.  
  156. (defconst custom-print-vector
  157.   nil
  158.   "If non-nil, an alist for printing of custom vector objects.  
  159. Pairs are of the form (pred . converter).  If the predicate is true
  160. for an object, the converter is called with the object and should
  161. return a string which will be printed with princ.  
  162. Also see custom-print-list.")
  163.  
  164.  
  165. (defun add-custom-print-list (pred converter)
  166.   "Add the pair, a PREDICATE and a CONVERTER, to custom-print-list.
  167. Any pair that has the same PREDICATE is first removed."
  168.   (setq custom-print-list (cons (cons pred converter) 
  169.                 (delq (assq pred custom-print-list)
  170.                       custom-print-list))))
  171. ;; e.g. (add-custom-print-list 'floatp 'float-to-string)
  172.  
  173.  
  174. (defun add-custom-print-vector (pred converter)
  175.   "Add the pair, a PREDICATE and a CONVERTER, to custom-print-vector.
  176. Any pair that has the same PREDICATE is first removed."
  177.   (setq custom-print-vector (cons (cons pred converter) 
  178.                   (delq (assq pred custom-print-vector)
  179.                     custom-print-vector))))
  180.  
  181.  
  182. ;;====================================================
  183. ;; Saving and restoring internal printing routines.
  184.  
  185. (defun CP::set-function-cell (symbol-pair)
  186.   (fset (car symbol-pair) 
  187.     (symbol-function (car (cdr symbol-pair)))))
  188.  
  189. (defun CP::internal-princ (object &optional stream)) ; dummy def
  190.  
  191. ;; Save internal routines.
  192. (if (not (fboundp 'CP::internal-prin1))
  193.     (mapcar 'CP::set-function-cell
  194.         '((CP::internal-prin1 prin1)
  195.           (CP::internal-princ princ)
  196.           (CP::internal-print print)
  197.           (CP::internal-prin1-to-string prin1-to-string)
  198.           (CP::internal-format format)
  199.           (CP::internal-message message)
  200.           (CP::internal-error error))))
  201.  
  202.  
  203. (defun install-custom-print-funcs ()
  204.   "Replace print functions with general, customizable, lisp versions.
  205. The internal subroutines are saved away and may be recovered with
  206. uninstall-custom-print-funcs."
  207.   (interactive)
  208.   (mapcar 'CP::set-function-cell
  209.       '((prin1 custom-prin1)
  210.         (princ custom-princ)
  211.         (print custom-print)
  212.         (prin1-to-string custom-prin1-to-string)
  213.         (format custom-format)
  214.         (message custom-message)
  215.         (error custom-error)
  216.         )))
  217.   
  218. (defun uninstall-custom-print-funcs ()
  219.   "Reset print functions to their internal subroutines."
  220.   (interactive)
  221.   (mapcar 'CP::set-function-cell
  222.       '((prin1 CP::internal-prin1)
  223.         (princ CP::internal-princ)
  224.         (print CP::internal-print)
  225.         (prin1-to-string CP::internal-prin1-to-string)
  226.         (format CP::internal-format)
  227.         (message CP::internal-message)
  228.         (error CP::internal-error)
  229.         )))
  230.  
  231. (defun custom-print-funcs-installed-p ()
  232.   "Return t if custom-print functions are currently installed, nil otherwise."
  233.   (eq (symbol-function 'custom-prin1) (symbol-function 'prin1)))
  234.  
  235. (put 'edebug-form-spec 'with-custom-print-funcs '(body))
  236.  
  237. (defmacro with-custom-print-funcs (&rest body)
  238.   (` (unwind-protect
  239.      (progn
  240.        (install-custom-print-funcs)
  241.        (,@ body))
  242.        (uninstall-custom-print-funcs))))
  243.  
  244. ;;===============================================================
  245. ;; Lisp replacements for prin1 and princ and for subrs that use prin1 
  246. ;; (or princ) -- so far only the printing and formatting subrs.
  247.  
  248. (defun custom-prin1 (object &optional stream)
  249.   "Replacement for standard prin1 that uses the appropriate
  250. printer depending on the values of `print-level' and `print-circle'.
  251.  
  252. Output the printed representation of OBJECT, any Lisp object.
  253. Quoting characters are printed when needed to make output that `read'
  254. can handle, whenever this is possible.
  255. Output stream is STREAM, or value of `standard-output' (which see)."
  256.   (CP::top-level object stream 'CP::internal-prin1))
  257.  
  258.  
  259. (defun custom-princ (object &optional stream)
  260.   "Same as custom-prin1 except no quoting."
  261.   (CP::top-level object stream 'CP::internal-princ))
  262.  
  263. (defvar prin1-chars) ; used dynamically below
  264.  
  265. (defun CP::prin1-to-string-func (c)
  266.   ;; Stream function for custom-prin1-to-string.
  267.   (setq prin1-chars (cons c prin1-chars)))
  268.  
  269. (defun custom-prin1-to-string (object)
  270.   "Replacement for standard prin1-to-string."
  271.   (let ((prin1-chars nil))
  272.     (custom-prin1 object 'CP::prin1-to-string-func)
  273.     (concat (nreverse prin1-chars))))
  274.  
  275.  
  276. (defun custom-print (object &optional stream)
  277.   "Replacement for standard print."
  278.   (CP::internal-princ "\n" stream)
  279.   (custom-prin1 object stream)
  280.   (CP::internal-princ "\n" stream))
  281.  
  282.  
  283. (defun custom-format (fmt &rest args)
  284.   "Replacement for standard format.
  285.  
  286. Calls format after first making strings for list or vector args.
  287. The format specification for such args should be %s in any case, so a
  288. string argument will also work.  The string is generated with
  289. custom-prin1-to-string, which quotes quotable characters."
  290.   (apply 'CP::internal-format fmt
  291.      (mapcar (function (lambda (arg)
  292.                  (if (or (listp arg) (vectorp arg))
  293.                  (custom-prin1-to-string arg)
  294.                    arg)))
  295.          args)))
  296.         
  297.   
  298.  
  299. (defun custom-message (fmt &rest args)
  300.   "Replacement for standard message that works like custom-format."
  301.   ;; It doesnt work to princ the result of custom-format
  302.   ;; because the echo area requires special handling
  303.   ;; to avoid duplicating the output.  CP::internal-message does it right.
  304.   ;; (CP::internal-princ (apply 'custom-format fmt args))
  305.   (apply 'CP::internal-message  fmt
  306.      (mapcar (function (lambda (arg)
  307.                  (if (or (listp arg) (vectorp arg))
  308.                  (custom-prin1-to-string arg)
  309.                    arg)))
  310.          args)))
  311.         
  312.  
  313. (defun custom-error (fmt &rest args)
  314.   "Replacement for standard error that uses custom-format"
  315.   (signal 'error (list (apply 'custom-format fmt args))))
  316.  
  317.  
  318. ;;=========================================
  319. ;; Support for custom prin1 and princ
  320.  
  321. ;; Declare variables used dynamically.
  322. (defvar circle-table)
  323. (defvar level)
  324.  
  325. (defun CP::internal-printer (object)) ; dummy def
  326. (defun CP::low-level-prin (object)) ; dummy def
  327. (defun CP::prin (object)) ; dummy def
  328.  
  329. (defun CP::top-level (object stream internal-printer)
  330.   ;; Set up for printing.
  331.   (let ((standard-output (or stream standard-output))
  332.     (circle-table (if print-circle (CP::preprocess-circle-tree object)))
  333.     (level (or print-level -1))
  334.     )
  335.  
  336.     (fset 'CP::internal-printer internal-printer)
  337.     (fset 'CP::low-level-prin 
  338.       (cond
  339.        ((or custom-print-list custom-print-vector)
  340.         'CP::custom-object)
  341.        ((or circle-table
  342.         print-level ; comment out for version 19
  343.         ;; Except that Emacs doesnt use print-level or print-length
  344.         ;; for vectors, whereas custom-print does.
  345.         (if custom-print-vectors
  346.             (or print-level print-length)))
  347.         'CP::object)
  348.        (t 'CP::internal-printer)))
  349.     (fset 'CP::prin (if circle-table 'CP::circular 'CP::low-level-prin))
  350.  
  351.     (CP::prin object)
  352.     object))
  353.  
  354.  
  355. (defun CP::object (object)
  356.   ;; Test object type and print accordingly.
  357.   ;; Could be called as either CP::low-level-prin or CP::prin.
  358.   (cond 
  359.    ((null object) (CP::internal-printer object))
  360.    ((consp object) (CP::list object))
  361.    ((vectorp object) (CP::vector object))
  362.    ;; All other types, just print.
  363.    (t (CP::internal-printer object))))
  364.  
  365.  
  366. (defun CP::custom-object (object)
  367.   ;; Test object type and print accordingly.
  368.   ;; Could be called as either CP::low-level-prin or CP::prin.
  369.   (cond 
  370.    ((null object) (CP::internal-printer object))
  371.  
  372.    ((consp object) 
  373.     (or (and custom-print-list
  374.          (CP::custom-object1 object custom-print-list))
  375.     (CP::list object)))
  376.  
  377.    ((vectorp object) 
  378.     (or (and custom-print-vector
  379.          (CP::custom-object1 object custom-print-vector))
  380.     (CP::vector object)))
  381.  
  382.    ;; All other types, just print.
  383.    (t (CP::internal-printer object))))
  384.  
  385.  
  386. (defun CP::custom-object1 (object alist)
  387.   ;; Helper for CP::custom-object.
  388.   ;; Print the custom OBJECT using the custom type ALIST.
  389.   ;; For the first predicate that matches the object, the corresponding
  390.   ;; converter is evaluated with the object and the string that results is
  391.   ;; printed with princ.  Return nil if no predicte matches the object.
  392.   (while (and alist (not (funcall (car (car alist)) object)))
  393.     (setq alist (cdr alist)))
  394.   ;; If alist is not null, then something matched.
  395.   (if alist
  396.       (CP::internal-princ
  397.        (funcall (cdr (car alist)) object) ; returns string
  398.        )))
  399.  
  400.  
  401. (defun CP::circular (object)
  402.   ;; Printer for prin1 and princ that handles circular structures.
  403.   ;; If OBJECT appears multiple times, and has not yet been printed,
  404.   ;; prefix with label; if it has been printed, use #n# instead.
  405.   ;; Otherwise, print normally.
  406.   (let ((tag (assq object circle-table)))
  407.     (if tag
  408.     (let ((id (cdr tag)))
  409.       (if (> id 0)
  410.           (progn
  411.         ;; Already printed, so just print id.
  412.         (CP::internal-princ "#")
  413.         (CP::internal-princ id)
  414.         (CP::internal-princ "#"))
  415.         ;; Not printed yet, so label with id and print object.
  416.         (setcdr tag (- id)) ; mark it as printed
  417.         (CP::internal-princ "#")
  418.         (CP::internal-princ (- id))
  419.         (CP::internal-princ "=")
  420.         (CP::low-level-prin object)
  421.         ))
  422.       ;; Not repeated in structure.
  423.       (CP::low-level-prin object))))
  424.  
  425.  
  426. ;;================================================
  427. ;; List and vector processing for print functions.
  428.  
  429. (defun CP::list (list)
  430.   ;; Print a list using print-length, print-level, and print-circle.
  431.   (if (= level 0)
  432.       (CP::internal-princ "#")
  433.     (let ((level (1- level)))
  434.       (CP::internal-princ "(")
  435.       (let ((length (or print-length 0)))
  436.  
  437.     ;; Print the first element always (even if length = 0).
  438.     (CP::prin (car list))
  439.     (setq list (cdr list))
  440.     (if list (CP::internal-princ " "))
  441.     (setq length (1- length))
  442.  
  443.     ;; Print the rest of the elements.
  444.     (while (and list (/= 0 length))
  445.       (if (and (listp list)
  446.            (not (assq list circle-table)))
  447.           (progn
  448.         (CP::prin (car list))
  449.         (setq list (cdr list)))
  450.  
  451.         ;; cdr is not a list, or it is in circle-table.
  452.         (CP::internal-princ ". ")
  453.         (CP::prin list)
  454.         (setq list nil))
  455.  
  456.       (setq length (1- length))
  457.       (if list (CP::internal-princ " ")))
  458.  
  459.     (if (and list (= length 0)) (CP::internal-princ "..."))
  460.     (CP::internal-princ ")"))))
  461.   list)
  462.  
  463.  
  464. (defun CP::vector (vector)
  465.   ;; Print a vector using print-length, print-level, and print-circle.
  466.   (if (= level 0)
  467.       (CP::internal-princ "#")
  468.     (let ((level (1- level))
  469.       (i 0)
  470.       (len (length vector)))
  471.       (CP::internal-princ "[")
  472.  
  473.       (if print-length
  474.       (setq len (min print-length len)))
  475.       ;; Print the elements
  476.       (while (< i len)
  477.     (CP::prin (aref vector i))
  478.     (setq i (1+ i))
  479.     (if (< i (length vector)) (CP::internal-princ " ")))
  480.  
  481.       (if (< i (length vector)) (CP::internal-princ "..."))
  482.       (CP::internal-princ "]")
  483.       ))
  484.   vector)
  485.  
  486.  
  487. ;;==================================
  488. ;; Circular structure preprocessing
  489.  
  490. (defun CP::preprocess-circle-tree (object)
  491.   ;; Fill up the table.  
  492.   (let (;; Table of tags for each object in an object to be printed.
  493.     ;; A tag is of the form:
  494.     ;; ( <object> <nil-t-or-id-number> )
  495.     ;; The id-number is generated after the entire table has been computed.
  496.     ;; During walk through, the real circle-table lives in the cdr so we
  497.     ;; can use setcdr to add new elements instead of having to setq the
  498.     ;; variable sometimes (poor man's locf).
  499.     (circle-table (list nil)))
  500.     (CP::walk-circle-tree object)
  501.  
  502.     ;; Reverse table so it is in the order that the objects will be printed.
  503.     ;; This pass could be avoided if we always added to the end of the
  504.     ;; table with setcdr in walk-circle-tree.
  505.     (setcdr circle-table (nreverse (cdr circle-table)))
  506.  
  507.     ;; Walk through the table, assigning id-numbers to those
  508.     ;; objects which will be printed using #N= syntax.  Delete those
  509.     ;; objects which will be printed only once (to speed up assq later).
  510.     (let ((rest circle-table)
  511.       (id -1))
  512.       (while (cdr rest)
  513.     (let ((tag (car (cdr rest))))
  514.       (cond ((cdr tag)
  515.          (setcdr tag id)
  516.          (setq id (1- id))
  517.          (setq rest (cdr rest)))
  518.         ;; Else delete this object.
  519.         (t (setcdr rest (cdr (cdr rest))))))
  520.     ))
  521.     ;; Drop the car.
  522.     (cdr circle-table)
  523.     ))
  524.  
  525.  
  526.  
  527. (defun CP::walk-circle-tree (object)
  528.   (let (read-equivalent-p tag)
  529.     (while object
  530.       (setq read-equivalent-p (or (numberp object) (symbolp object))
  531.         tag (and (not read-equivalent-p)
  532.              (assq object (cdr circle-table))))
  533.       (cond (tag
  534.          ;; Seen this object already, so note that.
  535.          (setcdr tag t))
  536.  
  537.         ((not read-equivalent-p)
  538.          ;; Add a tag for this object.
  539.          (setcdr circle-table
  540.              (cons (list object)
  541.                (cdr circle-table)))))
  542.       (setq object
  543.         (cond 
  544.          (tag ;; No need to descend since we have already.
  545.           nil)
  546.  
  547.          ((consp object)
  548.           ;; Walk the car of the list recursively.
  549.           (CP::walk-circle-tree (car object))
  550.           ;; But walk the cdr with the above while loop
  551.           ;; to avoid problems with max-lisp-eval-depth.
  552.           ;; And it should be faster than recursion.
  553.           (cdr object))
  554.  
  555.          ((vectorp object)
  556.           ;; Walk the vector.
  557.           (let ((i (length object))
  558.             (j 0))
  559.         (while (< j i)
  560.           (CP::walk-circle-tree (aref object j))
  561.           (setq j (1+ j))))))))))
  562.  
  563.  
  564.  
  565. ;;=======================================
  566. ;; Examples
  567.  
  568. '(progn
  569.    (progn
  570.      ;; Create some circular structures.
  571.      (setq circ-sym (let ((x (make-symbol "FOO"))) (list x x)))
  572.      (setq circ-list (list 'a 'b (vector 1 2 3 4) 'd 'e 'f))
  573.      (setcar (nthcdr 3 circ-list) circ-list)
  574.      (aset (nth 2 circ-list) 2 circ-list)
  575.      (setq dotted-circ-list (list 'a 'b 'c))
  576.      (setcdr (cdr (cdr dotted-circ-list)) dotted-circ-list)
  577.      (setq circ-vector (vector 1 2 3 4 (list 'a 'b 'c 'd) 6 7))
  578.      (aset circ-vector 5 (make-symbol "-gensym-"))
  579.      (setcar (cdr (aref circ-vector 4)) (aref circ-vector 5))
  580.      nil)
  581.  
  582.    (install-custom-print-funcs)
  583.    ;; (setq print-circle t)
  584.  
  585.    (let ((print-circle t))
  586.      (or (equal (prin1-to-string circ-list) "#1=(a b [1 2 #1# 4] #1# e f)")
  587.      (error "circular object with array printing")))
  588.  
  589.    (let ((print-circle t))
  590.      (or (equal (prin1-to-string dotted-circ-list) "#1=(a b c . #1#)")
  591.      (error "circular object with array printing")))
  592.  
  593.    (let* ((print-circle t)
  594.       (x (list 'p 'q))
  595.       (y (list (list 'a 'b) x 'foo x)))
  596.      (setcdr (cdr (cdr (cdr y))) (cdr y))
  597.      (or (equal (prin1-to-string y) "((a b) . #1=(#2=(p q) foo #2# . #1#))"
  598.         )
  599.      (error "circular list example from CL manual")))
  600.  
  601.    ;; There's no special handling of uninterned symbols in custom-print.
  602.    (let ((print-circle nil))
  603.      (or (equal (prin1-to-string circ-sym) "(#:FOO #:FOO)")
  604.      (error "uninterned symbols in list")))
  605.    (let ((print-circle t))
  606.      (or (equal (prin1-to-string circ-sym) "(#1=FOO #1#)")
  607.      (error "circular uninterned symbols in list")))
  608.  
  609.    (uninstall-custom-print-funcs)
  610.    )
  611.  
  612. 'end
  613.  
  614.